package com.saianfu.flowable

import com.saianfu.flowable.attendence.ApplyResult
import com.saianfu.flowable.attendence.ApplyType
import org.flowable.engine.HistoryService
import org.flowable.engine.RuntimeService
import org.flowable.engine.TaskService
import org.flowable.task.api.TaskQuery

/**
 * 针对人力资源平台
 */
object AttendanceFlowableEx {
    private const val maxNodeCount: Int = 6

    val nodeNameVariableNameList: MutableList<String> = MutableList(maxNodeCount) { index ->
        "nodeName${index + 1}"
    }

    /**
     * 流程执行人列表
     */
    val nodeAssigneeVariableNameList: MutableList<String> = MutableList(maxNodeCount) { index ->
        "nodeAssignee${index + 1}"
    }

    /**
     * 流程审批结果列表
     */
    val nodeResultVariableNameList: MutableList<String> = MutableList(maxNodeCount) { index ->
        "nodeResult${index + 1}"
    }

    /**
     * 流程跳过节点标记
     */
    val skipVariableNameList: MutableList<String> = MutableList(maxNodeCount) { index ->
        "skip${index + 1}"
    }

    /**
     * 申请类型
     */
    const val applyTypeVariableName = "applyType"

    /**
     * 创建申请
     */
    fun createApply(runtimeService: RuntimeService, applyType: ApplyType, nodeList: List<Pair<String, String>>, createApplyCB: (String) -> Unit) {
        val variables = mutableMapOf<String, Any>()
        variables["_FLOWABLE_SKIP_EXPRESSION_ENABLED"] = true

        variables[applyTypeVariableName] = applyType.code

        //初始设置审核结果都为-1，则流程会停止在下个节点上
        nodeResultVariableNameList.forEachIndexed { _, variableName ->
            variables[variableName] = -1
        }
        //默认全部跳过节点
        skipVariableNameList.forEachIndexed { _, variableName ->
            variables[variableName] = true
        }

        nodeList.forEachIndexed { index, pair ->
            val nodeNameVariableName = nodeNameVariableNameList[index]
            val nodeAssigneeVariableName = nodeAssigneeVariableNameList[index]
            val skipVariableName = skipVariableNameList[index]
            variables[nodeNameVariableName] = pair.first
            variables[nodeAssigneeVariableName] = pair.second
            variables[skipVariableName] = false
        }

        val process = runtimeService.startProcessInstanceByKey("AttendanceFlow001", variables)
        createApplyCB(process.processInstanceId)
    }

    /**
     * 创建任务查询句柄
     */
    private fun buildTaskQueryByVariables(taskService: TaskService, args: Map<String, Any?>): TaskQuery {
        val taskQuery = taskService.createTaskQuery()
        args.forEach { (k, v) ->
            taskQuery.processVariableValueEquals(k, v)
        }
        return taskQuery
    }

    /**
     * 查询我的流程,得到进行中的流程processId，通过ProcessId获取
     */
    fun pageActiveApply(taskService: TaskService, variables: Map<String, Any?>, candidateUser: String?,
                        orderBy: String, firstResult: Int, maxResults: Int): List<String> {
        val taskQuery = buildTaskQueryByVariables(taskService, variables)

        if (candidateUser.isNullOrEmpty()) {
            taskQuery.taskUnassigned()
        } else {
            taskQuery.taskAssigneeLikeIgnoreCase(candidateUser)
        }

        if (orderBy.contentEquals("desc")) {
            taskQuery.orderByTaskCreateTime().desc()
        } else {
            taskQuery.orderByTaskCreateTime().asc()
        }

        taskQuery.active()
        return taskQuery.listPage(firstResult, maxResults).map { it.processInstanceId }
    }

    /**
     * 查询我的流程,得到进行中的流程processId，通过ProcessId获取
     */
    fun listActiveApply(taskService: TaskService, variables: Map<String, Any?>, candidateUser: String?,
                        orderBy: String): List<String> {
        val taskQuery = buildTaskQueryByVariables(taskService, variables)

        if (candidateUser.isNullOrEmpty()) {
            taskQuery.taskUnassigned()
        } else {
            taskQuery.taskAssigneeLikeIgnoreCase(candidateUser)
        }

        if (orderBy.contentEquals("desc")) {
            taskQuery.orderByTaskCreateTime().desc()
        } else {
            taskQuery.orderByTaskCreateTime().asc()
        }

        taskQuery.active()
        return taskQuery.list().map { it.processInstanceId }
    }

    /**
     * 撤销流程
     */
    fun cancelApply(runtimeService: RuntimeService, instanceId: String, deleteReason: String?) {
        runtimeService.deleteProcessInstance(instanceId, deleteReason ?: "")
    }

    /**
     * 转审，重新设置该步骤审核人员
     */
    fun resetAssign(taskService: TaskService, instanceId: String, currentUser: String, newUser: String) {
        taskService.createTaskQuery().processInstanceId(instanceId)
                .list().forEach { task ->
                    if (task.assignee == currentUser) {
                        val assigneeList = MutableList(maxNodeCount) { "" }
                        taskService.getVariables(task.id).forEach { (vName, vVaule) ->
                            nodeAssigneeVariableNameList.forEachIndexed { index, s ->
                                if (vName == s) {
                                    assigneeList[index] = vVaule as String
                                    return@forEachIndexed
                                }
                            }
                        }
                        //查询变量中的流程执行人
                        val idx = assigneeList.indexOfFirst { name -> name == currentUser }
                        taskService.setVariable(task.id, nodeAssigneeVariableNameList[idx], newUser)
                        taskService.setAssignee(task.id, newUser)
                    }
                }
    }

    /**
     * 审批申请
     */
    fun handleApply(taskService: TaskService, instanceId: String, currentUser: String, handleRs: ApplyResult, handleCB: (String, Int, Boolean) -> Unit) {
        taskService.createTaskQuery().processInstanceId(instanceId)
                .list().forEach { task ->
                    if (task.assignee != currentUser) {
                        throw Exception("不是当前申请节点审批人")
                        return@forEach
                    }
                    val skipList = MutableList(maxNodeCount) { true }
                    val assigneeList = MutableList(maxNodeCount) { "" }
                    val nodeNameList = MutableList(maxNodeCount) { "" }
                    taskService.getVariables(task.id).forEach { (vName, vVaule) ->
                        nodeAssigneeVariableNameList.forEachIndexed { index, s ->
                            if (vName == s) {
                                assigneeList[index] = vVaule as String
                                return@forEachIndexed
                            }
                        }
                        skipVariableNameList.forEachIndexed { index, s ->
                            if (vName == s) {
                                skipList[index] = vVaule as Boolean
                                return@forEachIndexed
                            }
                        }

                        nodeNameVariableNameList.forEachIndexed { index, s ->
                            if (vName == s) {
                                nodeNameList[index] = vVaule as String
                                return@forEachIndexed
                            }
                        }

                    }

                    //当前流程的审核层级总数
                    val layerCount = skipList.count {
                        !it
                    }
                    //当前审核人属于第几个审核层级
                    val idx = assigneeList.indexOfFirst { name -> name == currentUser }

                    val variableCurrent = mutableMapOf<String, Any>()
                    //设置结果为通过
                    variableCurrent[nodeResultVariableNameList[idx]] = handleRs.code
                    taskService.complete(task.id, variableCurrent)

                    //审批节点
                    val nodeName = nodeNameList[idx]

                    //回调方法参数分别为流程节点名、审批结果、是否最后一个层级
                    if (idx + 1 == layerCount) {
                        //若审核通过，当前是最后一层审批
                        handleCB(nodeName, handleRs.code, true)
                    } else {
                        handleCB(nodeName, handleRs.code, handleRs.code == -1)
                    }

                }
    }

    /**
     * 获取历史参与审核的process id，按照创建时间的后先顺序
     */
    fun listHistoryApply(historyService: HistoryService, currentUser: String, firstResult: Int, maxResults: Int): List<String> {
        return historyService.createHistoricActivityInstanceQuery()
                .taskAssignee(currentUser)
                .orderByHistoricActivityInstanceStartTime().desc()
                .listPage(firstResult, maxResults)
                .filter { instance ->
                    instance.endTime != null
                }
                .map { instance ->
                    instance.processInstanceId
                }
    }
}